package com.ayu.shortlink.distribute.mq.handler.excel;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.ayu.shortlink.distribute.common.biz.user.UserContext;
import com.ayu.shortlink.distribute.common.constant.RedisCacheConstant;
import com.ayu.shortlink.distribute.dao.entity.CouponTaskDO;
import com.ayu.shortlink.distribute.dao.entity.CouponTemplateDO;
import com.ayu.shortlink.distribute.mq.basics.event.CouponTemplateExecuteEvent;
import com.ayu.shortlink.distribute.mq.producer.CouponTaskActuallyDistributeProducer;
import com.ayu.shortlink.distribute.utils.LuaScriptUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

/**
 * 进行Excel读取监听器并分发
 */
@RequiredArgsConstructor
@Slf4j
public class ExcelExecutorTaskListener extends AnalysisEventListener<CouponExcelObject> {
    private final StringRedisTemplate stringRedisTemplate;
    private final CouponTaskDO couponTask;
    private final CouponTaskActuallyDistributeProducer couponTaskActuallyDistributeProducer;
    private final CouponTemplateDO couponTemplateDO;
    private final static String STOCK_DECREMENT_AND_BATCH_SAVE_USER_RECORD_LUA_PATH = "lua/stock_decrement_and_batch_save_user_record.lua";
    @Getter
    private int count = 0;
    private static final Long USER_SIZE_EXPECT = 5000L;
    @Override
    public void invoke(CouponExcelObject excelObject, AnalysisContext analysisContext) {
        count++;
        String couponTaskId = String.valueOf(couponTask.getId());
        //先查进度
        //解决的问题：如果应用宕机的话，那这个数据怎么办
        String CouponTaskProcessKey = String.format(RedisCacheConstant.COUPON_EXECUTOR_TASK_PROCESS, couponTaskId);
        String progress = stringRedisTemplate.opsForValue().get(CouponTaskProcessKey);
        if (StrUtil.isNotBlank(progress) && Integer.parseInt(progress) > count) {
            count = Integer.parseInt(progress);
            return;
        }

        //用HuTool的单例容器存储Lua脚本
        DefaultRedisScript<Long> LuaScript = Singleton.get(STOCK_DECREMENT_AND_BATCH_SAVE_USER_RECORD_LUA_PATH, () -> {
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(STOCK_DECREMENT_AND_BATCH_SAVE_USER_RECORD_LUA_PATH)));
            redisScript.setResultType(Long.class);
            return redisScript;
        });

        // 获取模版存量
        StringBuilder stringBuilder = new StringBuilder()
                .append(couponTask.getShopNumber())
                .append("_")
                .append(couponTask.getCouponTemplateId());
        String couponTemplateKey = String.format(RedisCacheConstant.COUPON_TEMPLATE_CAPACITY_KEY,stringBuilder);
        // 获取用户的容量(Set存储)
        String batchUserSetKey = String.format(RedisCacheConstant.COUPON_DISTRIBUTE_BATCH_USER_SAVE_KEY, couponTaskId);
        // 执行Lua脚本
        Long combine = stringRedisTemplate.execute(LuaScript, ListUtil.of(couponTemplateKey,batchUserSetKey),excelObject.getUserId());
        // 获取Lua脚本的执行结果
        // 表示执行失败 只记录库存即可
        if(!LuaScriptUtil.isSuccess(combine)){
            stringRedisTemplate.opsForValue().set(CouponTaskProcessKey, String.valueOf(count));
            return;
        }
        //用户的一个集合
        Long userBatchSize = LuaScriptUtil.getUserBatchSize(combine);

        // 当用户集合满足等于5000时，要进行落库操作
        if((userBatchSize & USER_SIZE_EXPECT) == 0){
            CouponTemplateExecuteEvent event = CouponTemplateExecuteEvent.builder()
                    .couponTemplateId(String.valueOf(couponTask.getCouponTemplateId()))
                    .couponTaskId(couponTaskId)
                    .mail(excelObject.getMail())
                    .phone(excelObject.getPhone())
                    .batchUserSetSize(userBatchSize)
                    .shopNumber(UserContext.getShopNumber())
                    .notifyType(couponTask.getNotifyType())
                    .distributionEndFlag(Boolean.FALSE)
                    .couponTemplateConsumeRule(couponTemplateDO.getConsumeRule())
                    .couponTemplateId(couponTemplateDO.getId().toString())
                    .build();
            couponTaskActuallyDistributeProducer.sendMessage(event);
        }
        //同步进度
        stringRedisTemplate.opsForValue().set(CouponTaskProcessKey, String.valueOf(count));
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("读取Excel完成");
        //用来兜底
        CouponTemplateExecuteEvent event = CouponTemplateExecuteEvent.builder()
                .couponTemplateId(String.valueOf(couponTask.getCouponTemplateId()))
                .couponTaskId(String.valueOf(couponTask.getId()))
                .shopNumber(UserContext.getShopNumber())
                .notifyType(couponTask.getNotifyType())
                .distributionEndFlag(Boolean.TRUE)
                .build();
        couponTaskActuallyDistributeProducer.sendMessage(event);
    }
}
